package opt_go

import (
	"fmt"
	"math"
	"math/rand"
	"runtime"
	"strconv"
	"sync"
	"sync/atomic"
	"time"
)

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}

var wg sync.WaitGroup
var mutex sync.Mutex

func execute_run() {
	// S = 2
	wg.Add(2)
	go foo()
	go bar()

	wg.Wait()
}

func bar() {
	for i := 0; i < 10; i++ {
		fmt.Println("Foo:", i)
		time.Sleep(1 * time.Second)
	}
	// V(S)
	wg.Done()
}

func foo() {
	for i := 0; i < 10; i++ {
		time.Sleep(1 * time.Second)
		fmt.Println("Bar:", i)
	}
	//V(S)
	wg.Done()
}

// 竞争资源 count
var count int64

func excute_incrementor() {
	wg.Add(6)

	for i := 0; i < 3; i++ {
		go incrementor("index :" + strconv.Itoa(i))

		go incrementor_atomic("index atomic: " + strconv.Itoa(i))
	}
	wg.Wait()

	fmt.Println("final count :", count)
}

func incrementor(s string) {
	for i := 0; i < 20; i++ {
		// Sleep 释放当期CPU执行资源
		time.Sleep(time.Duration(rand.Intn(20)) * time.Millisecond)
		mutex.Lock()
		count++
		fmt.Println(s, i, "counter:", count)
		mutex.Unlock()
	}
	wg.Done()
}

func incrementor_atomic(s string) {
	for i := 0; i < 20; i++ {
		// Sleep 释放当期CPU执行资源
		time.Sleep(time.Duration(rand.Intn(20)) * time.Millisecond)
		atomic.AddInt64(&count, 1)
		fmt.Println(s, i, "counter:", count)

	}
	wg.Done()
}

func chin_go() {
	// 类似与阻塞队列(无缓存通道，生产->消费方式）
	ints := make(chan int, 10)
	wg.Add(2)
	go func() {
		for i := 0; i < 10; i++ {
			// 线程1 生产者（发送）, 把i发送到ints容器中
			ints <- i
		}
		close(ints)
		wg.Done()
	}()

	go func() {
		// 阻塞取值
		for i := range ints {
			fmt.Println(i)
		}
		wg.Done()
	}()
	wg.Wait()

}

func chin_go_2() {
	c := make(chan int)
	var wg2 sync.WaitGroup

	go func() {
		wg2.Add(1)
		for i := 0; i < 10; i++ {
			c <- i
		}
		wg2.Done()
	}()

	go func() {
		wg2.Add(1)
		for i := 0; i < 10; i++ {
			c <- i
		}
		wg2.Done()
	}()

	go func() {
		wg2.Add(1)
		for i := 0; i < 10; i++ {
			c <- i
		}
		wg2.Done()
	}()

	go func() {
		wg2.Wait()
		close(c)
	}()

	for i := range c {
		fmt.Println(i)
	}

}

func chin_go_3() {
	c := make(chan int)

	var wg sync.WaitGroup
	wg.Add(2)

	go func() {
		for i := 0; i < 10; i++ {
			c <- i
		}
		wg.Done()
	}()

	go func() {
		for i := 0; i < 10; i++ {
			c <- i
		}
		wg.Done()
	}()

	go func() {
		wg.Wait()
		close(c)
	}()

	for n := range c {
		fmt.Println(n)
	}

}

func chin_go_4() {

	ints := make(chan int)
	// 使用chan信号量同步ints
	bools := make(chan bool)

	go func() {
		for i := 0; i < 10; i++ {
			ints <- i
		}
		bools <- true
	}()

	go func() {
		for i := 0; i < 10; i++ {
			ints <- i
		}
		bools <- true
	}()

	go func() {
		<-bools
		<-bools
		close(ints)
	}()

	for i := range ints {
		fmt.Println("========", i)
	}
}

func chin_go_5() {
	c := make(chan int)
	done := make(chan bool)

	// 1 生产 to 2 消费模型
	go func() {
		for i := 0; i < 100000; i++ {
			c <- i
		}
		close(c)
	}()

	go func() {
		for n := range c {
			fmt.Println(n)
		}
		done <- true
	}()

	go func() {
		for n := range c {
			fmt.Println(n)
		}
		done <- true
	}()

	// 等待协程运行完
	<-done
	<-done
}

func incrementor_chan() chan int {
	out := make(chan int)
	go func() {
		for i := 0; i < 10; i++ {
			out <- i
		}
		close(out)
	}()
	return out
}

// c 消费
func puller(in <-chan int) chan int {
	out := make(chan int)
	go func() {
		var sum int
		for i := range in {
			sum += i
		}
		out <- sum
		close(out)
	}()
	return out
}

func chin_go_6() {
	out := incrementor_chan()
	ints := puller(out)
	for i := range ints {
		fmt.Println("sum is", i)
	}
}

func factorial_1(a int) chan int {
	out := make(chan int)
	go func() {
		total := 1
		for i := a; i > 0; i-- {
			total *= i
		}
		out <- total
		close(out)
	}()
	return out
}

func gen(nums ...int) chan int {
	out := make(chan int)
	go func() {
		for _, value := range nums {
			out <- value
		}
		close(out)
	}()
	return out
}

func sq(in chan int) chan float64 {
	out := make(chan float64)
	go func() {
		for n := range in {
			out <- math.Pow(float64(n), 2)
		}
		close(out)
	}()

	return out
}
